#!/usr/bin/env python3
# -*- coding: utf-8 -*-

""" Ce module permet d'accéder à une base de données de valeurs mobilières."""

__auteur__ = "MAGAR207"
__coequipiers__ = "CHBRU14", "MAPAR9", "OLGAG28"
__date__ = "21-10-11"

import datetime
import urllib.request
import csv
import codecs

# {0} correspond au titre de l'action;
# {1} aux options désirées.
YAHOO_VALEURS = "http://ca.finance.yahoo.com/d/quotes.csv?s={0}&f={1}"

# Requête à effectuer pour obtenir les champs : nom (n), symbol (s), valeur de
# la dernière transaction (l1), temps de la dernière transaction (t1), date de
# la dernière transaction (d1), valeur à l'ouverture (o), valeur la plus haute
# aujourd'hui (h) et valeur la plus basse aujourd'hui (g).
OPTIONS = "nsl1t1d1ohg"

# {0} correspond au titre de l'action;
# {1} correspond au mois de début, janvier = 0, décembre = 11
# {2} correspond au jour de début
# {3} correspond à l'année de début
# {4} correspond au mois de fin, janvier = 0, décembre = 11
# {5} correspond au jour de fin
# {6} correspond à l'année de fin
YAHOO_HISTORIQUE = ("http://ichart.finance.yahoo.com/table.csv?s={0}&g=d"
                    "&a={1}&b={2}&c={3}&d={4}&e={5}&f={6}")

class TitreInvalide(Exception): pass

# Le module urllib nous renvoie les données sous forme de "bytes"
# (c'est-à-dire une suite d'octets). Pour pouvoir les utiliser, nous
# devons d'abord les convertir en un encodage connu (ici, UTF-8).
decodeur = codecs.getreader('utf-8')

def infoTitre(titre):
    """ Cette fonction retourne les informations relatives au titre
    *titre*, telles que fournies par la base de données «Yahoo Finance».
    Soulève une exception de type *TitreInvalide* si le titre demandé
    est inconnu. Les informations sont retournées dans un dictionnaire
    possédant les clés suivantes: nom, valeur, heure, date, ouverture,
    haut, bas. """
    requete = YAHOO_VALEURS.format(titre, OPTIONS)
    # La réponse est décodée dès qu'elle est reçue (la réponse sous
    # forme de bytes ne présente pas d'intérêt)
    reponse = decodeur(urllib.request.urlopen(requete))
    
    # Le module csv décode les données pour nous.
    # On sélectionne uniquement la première ligne.
    data = tuple(csv.reader(reponse))[0]
    
    info = {"nom" : data[0],
            "valeur" : float(data[2]),
            "heure" : data[3],
            "date" : data[4],
            "ouverture" : (float(data[5]) if data[5]!='N/A' else None),
            "haut" : (float(data[6]) if data[6]!='N/A' else None),
            "bas" : (float(data[7]) if data[7]!='N/A' else None)
            }
    if info['valeur'] == 0:
        raise TitreInvalide("titre '{0}' invalide".format(titre))
    return info

def historiqueTitre(titre, jours):
    """ Cette fonction retourne sous la forme d'une liste l'historique
    des valeurs du titre *titre* pour les *jours* jours précédents.
    Soulève une exception de type *TitreInvalide* si le titre demandé
    est inconnu. L'historique est retourné sous la forme d'une liste de
    tuples (date, valeur) en ordre croissant de date. """
    fin = datetime.date.today()
    debut = fin - datetime.timedelta(days=jours)
    
    # Préparation des champs de la requête (ne pas oublier que janvier = 0)
    requete = YAHOO_HISTORIQUE.format(titre,
                                      debut.month-1,
                                      debut.day,
                                      debut.year,
                                      fin.month-1,
                                      fin.day,
                                      fin.year
                                      )
    try:
        # La réponse est décodée dès qu'elle est reçue (la réponse sous
        # forme de bytes ne présente pas d'intérêt)
        reponse = decodeur(urllib.request.urlopen(requete))
    except urllib.error.HTTPError:
        raise TitreInvalide("titre '{0}' invalide".format(titre))
    
    resultat = []
    # Laisser tomber la première ligne (celle contenant les noms des champs)
    for data in tuple(csv.reader(reponse))[1:]:
        # À ce moment-ci, data contient une ligne sous forme d'une liste
        # de chaînes de caractères. Chacun des élément de cette liste est
        # un champ du CSV. Il nous suffit d'aller chercher ceux qui
        # nous intéressent.
        resultat.append((data[0], float(data[4])))

    # On veut les taux à la fermeture en ordre croissant de date
    return list(reversed(resultat))

if __name__ == '__main__':
    print("Informations pour le titre 'goog':", infoTitre('goog'))
    print("Historique des 15 derniers jours:\n",
          historiqueTitre('goog', 15), sep='')
